package com.aprilTomCat.TestTomcat;

import com.aprilTomCat.Servlet.HttpServlet;
import com.aprilTomCat.conf.ServletConfigMapping;
import com.aprilTomCat.util.ResponseUtil;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyTomcat {
    Request request  = new Request();
    //启动tomcat的主方法
    public void startUp() throws  Exception {
        //加载servlet信息
        ServletConfigMapping.initServlet(); //启动阶段

        //创建线程池
        ThreadPoolExecutor executor=new ThreadPoolExecutor(5, 10, 100,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),
                r -> new Thread(r),
        new ThreadPoolExecutor.CallerRunsPolicy()
        );

        // 1. serverSelector负责轮询是否有新的连接，服务端监测到新的连接之后，不再创建一个新的线程，
        // 而是直接将新连接绑定到clientSelector上，这样就不用 IO 模型中 1w 个 while 循环在死等
        Selector serverSelector = Selector.open();
        // 2. clientSelector负责轮询连接是否有数据可读
        Selector clientSelector = Selector.open();
        executor.execute(()->{
            try {
                // 对应IO编程中服务端启动
                ServerSocketChannel listenerChannel = ServerSocketChannel.open();
                listenerChannel.socket().bind(new InetSocketAddress(8080));
                listenerChannel.configureBlocking(false);
                listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);

                while (true) {
                    // 监测是否有新的连接，这里的1指的是阻塞的时间为 1ms
                    if (serverSelector.select(1) > 0) {
                        handlerNIO(serverSelector,clientSelector);
                    }
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        });
        executor.execute(()->{
            try {
                while (true) {
                    // (2) 批量轮询是否有哪些连接有数据可读，这里的1指的是阻塞的时间为 1ms
                    if (clientSelector.select(1) > 0) {
                        getInputNIO(clientSelector);
                    }
                }
            } catch (Exception ignored) {
            }
        });

//          bio
//        //定义ServerSocket8080端口
//        ServerSocket serverSocket = new ServerSocket(8080);
//        while (true){
//            Socket socket = serverSocket.accept();
//            executor.execute(new Runnable() {
//                @Override
//                public void run() {
//                    try {
//                        handler(socket);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            });
//        }
    }
    //解析用户请求数据 nio
    public void handlerNIO(Selector serverSelector,Selector clientSelector) throws Exception {
        Set<SelectionKey> set = serverSelector.selectedKeys();
        Iterator<SelectionKey> keyIterator = set.iterator();
        while (keyIterator.hasNext()) {
            SelectionKey key = keyIterator.next();

            if (key.isAcceptable()) {
                try {
                    // (1) 每来一个新连接，不需要创建一个线程，而是直接注册到clientSelector
                    SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
                    clientChannel.configureBlocking(false);
                    clientChannel.register(clientSelector, SelectionKey.OP_READ);
                } finally {
                    keyIterator.remove();
                }
            }

        }

    }
    //解析http请求 nio
    public void getInputNIO(Selector clientSelector) throws Exception {
        Set<SelectionKey> set = clientSelector.selectedKeys();
        Iterator<SelectionKey> keyIterator = set.iterator();
        String content=null;
        SocketChannel clientChannel = null;
        ByteBuffer byteBuffer=null;
        while (keyIterator.hasNext()) {
            SelectionKey key = keyIterator.next();

            if (key.isReadable()) {
                try {
                    clientChannel = (SocketChannel) key.channel();
                    byteBuffer = ByteBuffer.allocate(1024);
                    // (3) 面向 Buffer
                    clientChannel.read(byteBuffer);
                    byteBuffer.flip();
                    content= new String(byteBuffer.array());

                } finally {
                    keyIterator.remove();
                    key.interestOps(SelectionKey.OP_READ);
                }
            }

        }
        System.out.println(content);
        if(content.equals("")){
            System.out.println("你有一个空请求......");
        }else {
            String firstLine = content.split("\\n")[0];
            request.setMethod(firstLine.split("\\s")[0]);
            request.setUrl(firstLine.split("\\s")[1]);
        }
        //获取输出通道、获取输出流
        Response response = new Response(byteBuffer);
        response.setSocketChannel(clientChannel);
//        if(response.getSocketChannel()==clientChannel&&response.getBuffer()==byteBuffer){
//            byteBuffer=ByteBuffer.wrap(ResponseUtil.getResponseHeader200("this is get Method1").getBytes(StandardCharsets.UTF_8));
//
//        }else {
//            byteBuffer=ByteBuffer.wrap(ResponseUtil.getResponseHeader200("this is get Method").getBytes(StandardCharsets.UTF_8));
//
//        }
//        clientChannel.write(byteBuffer);
//        clientChannel.close();

//
        if(request.getUrl().equals("")){
            //放回404
            response.getWriteNIO(ResponseUtil.getResponseHeader404());
        }else if(ServletConfigMapping.classMap.get(request.getUrl()) == null){
            //访问的是静态资源
            response.GetWriteHtmlNIO(request.getUrl());
        }else {
            //访问的是动态资源
            dispatch(request,response);
        }
        //clientChannel.close();

    }
    //解析用户请求数据
    public void handler(Socket socket) throws Exception {
        InputStream inputStream = socket.getInputStream();
        getInput(inputStream);  //解析http请求

        //获取输出通道、获取输出流
        Response response = new Response(socket.getOutputStream());

        if(request.getUrl().equals("")){
            //放回404
            System.out.println(1+"----------------");
            response.getWrite(ResponseUtil.getResponseHeader404());
        }else if(ServletConfigMapping.classMap.get(request.getUrl()) == null){
            //访问的是静态资源
            response.GetWriteHtml(request.getUrl());
        }else {
            //访问的是动态资源
            dispatch(request,response);
        }


    }
    //解析http请求
    public void getInput(InputStream inputStream) throws IOException {
        int count = 0;
        while (count ==0){
            count = inputStream.available();
        }
        byte[] bytes = new byte[count];
        inputStream.read(bytes);
        String content = new String(bytes);
        System.out.println(content);
        if(content.equals("")){
            System.out.println("你有一个空请求......");
        }else {
            String firstLine = content.split("\\n")[0];
            request.setMethod(firstLine.split("\\s")[0]);
            request.setUrl(firstLine.split("\\s")[1]);
        }
    }
    //获取类对象生成servlet对象
    public void dispatch(Request request,Response response) throws  Exception {
        Class<HttpServlet> servletClass = ServletConfigMapping.classMap.get(request.getUrl());
        if(servletClass !=null){
            HttpServlet servlet = servletClass.newInstance(); //生成servlet对象
            servlet.service(request,response);
        }
    }

    public static void main(String[] args) throws Exception {
        MyTomcat myTomcat=new MyTomcat();
        myTomcat.startUp();
    }
}
